cormoran.me



cui tetris

tetris

何か簡単なゲームが必要だったのでテトリスもどきを作ってみました。ncursesを使ってます。

下がプログラムです。最低限の機能しかつけていませんがちょっと楽しいです。まあ、emacsにtetrisは入っているのでそれで遊べばいいのですが。

language: cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 #include <ncurses.h> #include <unistd.h> #include<cstdio> #include<cstdlib> #include<ctime> #include <utility> #include <string> using namespace std; #define TIMEOUT 10 //キーボード入力タイムアウト #define NEXT_BLOCK_X 13 #define NEXT_BLOCK_Y 0 #define SCORE_X 13 #define SCORE_Y 20 #define MAP_X (10+2) //文字 壁2つ #define MAP_Y (20+1+5) //行 下ガード+未表示領域 #define MAP_NOT_SHOW_NUM 5 #define BLOCK_H_W 5 #define BLOCK_NUM 7 bool block_can_rot[BLOCK_NUM]={0,1,1,1,1,1,1}; char block_data[BLOCK_NUM][5][5]= { {{0,0,0,0,0}, {0,2,2,0,0}, {0,2,2,0,0}, {0,0,0,0,0}, {0,0,0,0,0} }, {{0,0,0,0,0}, {0,0,3,0,0}, {0,3,3,3,0}, {0,0,0,0,0}, {0,0,0,0,0} }, {{0,0,0,0,0}, {0,0,0,4,0}, {0,0,4,4,0}, {0,0,4,0,0}, {0,0,0,0,0} }, {{0,0,5,0,0}, {0,0,5,0,0}, {0,0,5,0,0}, {0,0,5,0,0}, {0,0,0,0,0} }, {{0,0,0,0,0}, {0,6,0,0,0}, {0,6,6,0,0}, {0,0,6,0,0}, {0,0,0,0,0} }, {{0,0,0,0,0}, {0,0,7,7,0}, {0,0,7,0,0}, {0,0,7,0,0}, {0,0,0,0,0} }, {{0,0,0,0,0}, {0,8,8,0,0}, {0,0,8,0,0}, {0,0,8,0,0}, {0,0,0,0,0} }, }; enum Direction{UP,DOWN,RIGHT,LEFT}; typedef struct block { char data[BLOCK_H_W][BLOCK_H_W]; bool can_rot; pair<int,int> point; block() { reset(0); } void reset(char type) { char x,y; for(y=0;y<BLOCK_H_W;y++) for(x=0;x<BLOCK_H_W;x++) data[y][x]=block_data[type][y][x]; can_rot=block_can_rot[type]; point.first=3; point.second=0; } bool rotate(Direction dir,char map[MAP_Y][MAP_X]) { if(can_rot){ char next_data[BLOCK_H_W][BLOCK_H_W]; //取り敢えず回転させてみる if(dir==RIGHT)//右移転 { char x,y; for(y=0;y<BLOCK_H_W;y++) for(x=0;x<BLOCK_H_W;x++) next_data[x][(BLOCK_H_W-1)-y]=data[y][x]; } else if(dir==LEFT) { char x,y; for(y=0;y<BLOCK_H_W;y++) for(x=0;x<BLOCK_H_W;x++) next_data[(BLOCK_H_W-1)-x][y]=data[y][x]; } //衝突チェック if(can_move(point.first,point.second,next_data,map)){ char x,y; for(y=0;y<BLOCK_H_W;y++) for(x=0;x<BLOCK_H_W;x++) data[y][x]=next_data[y][x]; return true; } } return false; } //x,y 左上端座標:負になることもある bool can_move(int x,int y,char next_data[BLOCK_H_W][BLOCK_H_W],char map[MAP_Y][MAP_X]) { char i,j; for(i=0;i<BLOCK_H_W;i++) for(j=0;j<BLOCK_H_W;j++) if(x+i>=0 && y+j>=0 && x+i<MAP_X && y+i<MAP_Y) if(next_data[j][i]!=0 && map[y+j][x+i]!=0) return false; return true; } bool move(Direction dir,char map[MAP_Y][MAP_X]) { switch(dir){ case RIGHT://右 if(can_move(point.first+1,point.second,data,map)){ point.first+=1; return true; } break; case LEFT://左 if(can_move(point.first-1,point.second,data,map)){ point.first-=1; return true; } break; case UP://上 if(can_move(point.first,point.second-1,data,map)){ point.second-=1; return true; } break; case DOWN://下 if(can_move(point.first,point.second+1,data,map)){ point.second+=1; return true; } break; } return false; } }block; void show_map(char map[MAP_Y][MAP_X]) { int x,y; for(y=0;y<MAP_Y-MAP_NOT_SHOW_NUM;y++) for(x=0;x<MAP_X;x++){ attrset(COLOR_PAIR(map[y+MAP_NOT_SHOW_NUM][x])); mvaddstr(y,x," "); } } void show_map(block *myblock,char map[MAP_Y][MAP_X]) { int x,y; for(y=0;y<MAP_Y-MAP_NOT_SHOW_NUM;y++) for(x=0;x<MAP_X;x++){ attrset(COLOR_PAIR(map[y+MAP_NOT_SHOW_NUM][x])); mvaddstr(y,x," "); } for(y=0;y<BLOCK_H_W;y++) for(x=0;x<BLOCK_H_W;x++) if(myblock->data[y][x]!=0 && myblock->point.second-MAP_NOT_SHOW_NUM+y>=0){ attrset(COLOR_PAIR(myblock->data[y][x])); mvaddstr(myblock->point.second-MAP_NOT_SHOW_NUM+y,myblock->point.first+x," "); } } void show_nextblock(int block_num) { int x,y; for(y=0;y<BLOCK_H_W;y++) for(x=0;x<BLOCK_H_W;x++) { attrset(COLOR_PAIR(block_data[block_num][y][x])); mvaddstr(y+NEXT_BLOCK_Y,x+NEXT_BLOCK_X," "); } } void show_score(int score) { attrset(COLOR_PAIR(0)); mvprintw(SCORE_Y,SCORE_X,"SCORE:%d",score); } int init() { initscr();//window初期化 noecho();//キー入力を表示しない cbreak();//キー入力をすぐに受け付ける curs_set(0);//カーソル非表示 start_color();//カラーの初期化? /*色ペアの設定 (番号,前景色,背景色) 0は前白,後黒になってるらしい*/ init_pair(1,COLOR_BLACK,COLOR_WHITE); init_pair(2, COLOR_BLACK, COLOR_RED); init_pair(3, COLOR_BLACK, COLOR_GREEN); init_pair(4,COLOR_BLACK,COLOR_BLUE); init_pair(5,COLOR_BLACK,COLOR_YELLOW); init_pair(6,COLOR_BLACK,COLOR_CYAN); init_pair(7,COLOR_BLACK,COLOR_MAGENTA); init_pair(8,COLOR_BLACK,COLOR_BLUE); bkgd(COLOR_PAIR(0));//ターミナルの背景黒、文字白 wtimeout(stdscr,TIMEOUT);//getchのタイムアウト設定 keypad(stdscr, TRUE); //矢印キー使用する srand(time(NULL));//乱数列初期化 return 0; } /* キー入力を反映する関数 入力がなければfalse */ bool key_input(block *myblock,char map[MAP_Y][MAP_X]) { int keyinput; keyinput=getch(); switch(keyinput){ case KEY_RIGHT: myblock->move(RIGHT,map);break; case KEY_LEFT: myblock->move(LEFT,map);break; case KEY_UP: myblock->rotate(LEFT,map);break; case KEY_DOWN: myblock->move(DOWN,map);break; case 'c': endwin(); exit(0); default :return false; } return true; } void lock_myblock(block *myblock,char map[MAP_Y][MAP_X]) { int x,y; for(y=0;y<BLOCK_H_W;y++) for(x=0;x<BLOCK_H_W;x++) if(myblock->data[y][x]!=0)map[myblock->point.second+y][myblock->point.first+x]=myblock->data[y][x]; } /* 揃ったラインを消す関数 return:消したライン数 */ int delete_lines(char map[MAP_Y][MAP_X]) { int x,y,cnt=0; for(y=MAP_Y-2;y>=0;y--){ bool flg=true; for(x=1;x<MAP_X-1;x++) if(map[y][x]==0)flg=false; if(flg)cnt++; else if(cnt) for(x=1;x<MAP_X-1;x++) map[y+cnt][x]=map[y][x]; } return cnt; } void gameover(char map[MAP_Y][MAP_X]) { int x,y; for(y=0;y<MAP_Y;y++) for(x=0;x<MAP_X;x++) map[y][x]=1; show_map(map); } int play(int difficulty) { int next_myblock_num; char map[MAP_Y][MAP_X]; block myblock; int score=0; //マップリセット int x,y; for(y=0;y<MAP_Y;y++) for(x=0;x<MAP_X;x++) { if(x==0 || x== MAP_X-1)map[y][x]=1; else if(y==MAP_Y-1)map[y][x]=1; else map[y][x]=0; } while(true) { for(int i=0;i<20-difficulty;i++) { key_input(&myblock,map); //タイム追加 usleep(2000); } if(myblock.move(DOWN,map)==false){ //下に落とせなかったら固定 lock_myblock(&myblock,map); //上端で落とせなかったら終わり if(myblock.point.second<=MAP_NOT_SHOW_NUM){ gameover(map); return 0; } myblock.reset(next_myblock_num); next_myblock_num=rand()%BLOCK_NUM; } score+=delete_lines(map)*10; show_map(&myblock,map); show_nextblock(next_myblock_num); show_score(score); } } int main() { char nextblock; init(); play(0); endwin(); }